#include "../../core/graphic/render_item.h"
#include <GLES/gl.h>

extern unsigned int g_viewportWidth;
extern unsigned int g_viewportHeight;

struct ANDROID_VEC {
	float x, y, z, w;
};
struct ANDROID_MAT {
	ANDROID_VEC x, y, z, w;
};

static KRenderState mCurrentRS;
static int pirmTypeMap[] = {
	GL_TRIANGLE_STRIP,
	GL_TRIANGLES,
	GL_LINE_STRIP,
	GL_LINES
};
static unsigned int g_BGColor = 0;

#define COLOR_BIT	0x0001
#define TEXCRD_BIT  0x0002
struct ANDROID_HW_BUFFER
{
	void* pVB;
	KPrimType primType;
	int vertexFVF;
	unsigned int vertexCount;
	ANDROID_HW_BUFFER() {pVB = NULL; vertexCount = 0;}
};

void Android_DrawArray(KPrimType type, int fvf, const void* pData, unsigned int vertCnt)
{
	BYTE* pByteData = (BYTE*)pData;
	int stride = sizeof(float) * 3;
	BYTE* pVert = pByteData;
	BYTE* pColor = NULL;
	BYTE* pTexcrd = NULL;
	pByteData += sizeof(float) * 3;
	if (fvf & COLOR_BIT) {
		pColor = pByteData;
		pByteData += 4;
		stride += 4;
	}
	if (fvf & TEXCRD_BIT) {
		pTexcrd = pByteData;
		stride += sizeof(float) * 2;
	}
	
	if (pColor) {
		glColorPointer(4, GL_UNSIGNED_BYTE, stride, pColor);
		glEnableClientState(GL_COLOR_ARRAY);
	}
	else
		glDisableClientState(GL_COLOR_ARRAY);
		
	if (pTexcrd) {
		glTexCoordPointer(2, GL_FLOAT, stride, pTexcrd);
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	}
	else
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		
	glVertexPointer(3, GL_FLOAT, stride, pVert);
	
	glDrawArrays(pirmTypeMap[type], 0, vertCnt);
}

void ConvertRGBA8_to_Float(KColor clr, float* pOutFloat)
{
	pOutFloat[0] = float((clr>>0) & 0x0000ff) / 255.0f;
	pOutFloat[1] = float((clr>>8) & 0x0000ff) / 255.0f;
	pOutFloat[2] = float((clr>>16) & 0x0000ff) / 255.0f;
	pOutFloat[3] = float((clr>>24) & 0x0000ff) / 255.0f;
}

void ApplyBlendState(const KRenderState& rs)
{
	switch (rs.mBlendMode) {
	case KRenderState::eDisableBlend:
		glDisable(GL_BLEND);
		break;
	case KRenderState::eAlphaBlend:
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		break;
	case KRenderState::eAddBlend:
		glEnable(GL_BLEND);
		glBlendFunc(GL_ONE, GL_ONE);
		break;
	}
}

void ApplyTexEnvColor(KColor color)
{
	float floatClr[4];
	ConvertRGBA8_to_Float(color, floatClr);
	glColor4f(floatClr[0], floatClr[1], floatClr[2], floatClr[3]);
}

void KDrawManager::SetRenderState(const KRenderState& rs)
{
	if (mCurrentRS.mBlendMode != rs.mBlendMode)
		ApplyBlendState(rs);

	ApplyTexEnvColor(rs.mModulateColor);

	if (rs.mTexture) {
		glEnable(GL_TEXTURE_2D);
		rs.mTexture->Bind();
	}
	else {
		glDisable(GL_TEXTURE_2D);
	}
	
	mCurrentRS = rs;
}

void SetWorldMatrix(const KDrawLocal& local)
{
	glMatrixMode(GL_MODELVIEW);

	ANDROID_MAT transMat;
	//memset(&transMat, 0, sizeof(ANDROID_MAT));
	transMat.x.x = local.rot.mCosTheta;
	transMat.y.x = -local.rot.mSinTheta;
	transMat.z.x = 0;
	transMat.w.x = local.x;

	transMat.x.y = local.rot.mSinTheta;
	transMat.y.y = local.rot.mCosTheta;
	transMat.z.y = 0;
	transMat.w.y = local.y;

	transMat.x.z = 0;
	transMat.y.z = 0;
	transMat.z.z = 1;
	transMat.w.z = 0;

	transMat.x.w = 0;
	transMat.y.w = 0;
	transMat.z.w = 0;
	transMat.w.w = 1;

	glLoadMatrixf((float*)&transMat);
}

void KDrawManager::Draw_P(const VERTEX_P*  pData, const KDrawLocal& local, KPrimType type, unsigned int vertCnt)
{
	SetWorldMatrix(local);
	Android_DrawArray(type, 0, pData, vertCnt);
}

void KDrawManager::Draw_PC(const VERTEX_PC*  pData, const KDrawLocal& local, KPrimType type, unsigned int vertCnt)
{
	glDisable(GL_TEXTURE_2D);
	ApplyTexEnvColor(0xffffffff);
	SetWorldMatrix(local);
	Android_DrawArray(type, COLOR_BIT, pData, vertCnt);
}

void KDrawManager::Draw_PT(const VERTEX_PT*  pData, const KDrawLocal& local, KPrimType type, unsigned int vertCnt)
{
	SetWorldMatrix(local);
	Android_DrawArray(type, TEXCRD_BIT, pData, vertCnt);
}

void KDrawManager::Draw_HWBuf(const KDrawLocal& local, HW_BufferPtr pBuffer)
{
	ANDROID_HW_BUFFER* pPSPBuffer = (ANDROID_HW_BUFFER*)pBuffer;
	SetWorldMatrix(local);
	
	Android_DrawArray(pPSPBuffer->primType, pPSPBuffer->vertexFVF, pPSPBuffer->pVB, pPSPBuffer->vertexCount);
}

HW_BufferPtr KDrawManager::CreateHWBuffer(const VERTEX_P*  pData, KPrimType type, unsigned int vertCnt)
{
	ANDROID_HW_BUFFER* pBuffer = new ANDROID_HW_BUFFER;

	pBuffer->primType = type;
	pBuffer->vertexCount = vertCnt;
	pBuffer->vertexFVF = 0;
	pBuffer->pVB = malloc(sizeof(VERTEX_P) * vertCnt);
	memcpy(pBuffer->pVB, pData, sizeof(VERTEX_P) * vertCnt);
	
	return pBuffer;
}

HW_BufferPtr KDrawManager::CreateHWBuffer(const VERTEX_PC* pData, KPrimType type, unsigned int vertCnt)
{
	ANDROID_HW_BUFFER* pBuffer = new ANDROID_HW_BUFFER;

	pBuffer->primType = type;
	pBuffer->vertexCount = vertCnt;
	pBuffer->vertexFVF = COLOR_BIT;
	pBuffer->pVB = malloc(sizeof(VERTEX_PC) * vertCnt);
	memcpy(pBuffer->pVB, pData, sizeof(VERTEX_PC) * vertCnt);

	return pBuffer;
}

HW_BufferPtr KDrawManager::CreateHWBuffer(const VERTEX_PT* pData, KPrimType type, unsigned int vertCnt)
{
	ANDROID_HW_BUFFER* pBuffer = new ANDROID_HW_BUFFER;

	pBuffer->primType = type;
	pBuffer->vertexCount = vertCnt;
	pBuffer->vertexFVF = TEXCRD_BIT;
	pBuffer->pVB = malloc(sizeof(VERTEX_PT) * vertCnt);
	memcpy(pBuffer->pVB, pData, sizeof(VERTEX_PT) * vertCnt);

	return pBuffer;
}

void KDrawManager::DeleteHWBuffer(HW_BufferPtr pBuffer)
{
	ANDROID_HW_BUFFER* pPSPBuffer = (ANDROID_HW_BUFFER*)pBuffer;
	if (pPSPBuffer) free(pPSPBuffer->pVB);
	delete pPSPBuffer;
}

static KRenderState defaultRS;

void KDrawManager::Begin()
{	
	mCurrentRS = defaultRS;

	glEnableClientState(GL_VERTEX_ARRAY);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

	glEnable(GL_ALPHA_TEST);
	glAlphaFunc(GL_GREATER, 0);

	glDisable(GL_DEPTH_TEST);
	glDisable(GL_TEXTURE_2D);
	ApplyBlendState(mCurrentRS);

	ApplyTexEnvColor(mCurrentRS.mModulateColor);

	float color4[4];
	ConvertRGBA8_to_Float(g_BGColor, color4);
	glClearColor(color4[0], color4[1], color4[2], color4[3]);
	glClear(GL_COLOR_BUFFER_BIT);
}

void KDrawManager::End()
{
	glFlush();
}

void KDrawManager::SetupView(float w, float h, const KVec2& center, KColor bgClr)
{
	g_BGColor = bgClr;
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	
	glOrthof(
		-w*0.5f, w*0.5f,
		-h*0.5f, h*0.5f,
		-1, 1);

	glTranslatef(-center[0], -center[1], 0);
}

void KDrawManager::DrawSprite(const KDrawLocal& local, KTexture* pTexture, const KSpriteRect& rect, KColor color)
{
	glEnable(GL_TEXTURE_2D);
	pTexture->Bind();

	float hx = (float)rect.w;
	float hy = (float)rect.h;
	float u0 = (float)rect.sx / (float)pTexture->mWidth;
	float u1 = (float)(rect.sx+rect.w) / (float)pTexture->mWidth;
	float v0 = (float)rect.sy / (float)pTexture->mHeight;
	float v1 = (float)(rect.sy+rect.h) / (float)pTexture->mHeight;

	ApplyTexEnvColor(color);

	glMatrixMode(GL_MODELVIEW);
	ANDROID_MAT transMat;
	//memset(&transMat, 0, sizeof(ANDROID_MAT));
	transMat.x.x = local.rot.mCosTheta;
	transMat.y.x = -local.rot.mSinTheta;
	transMat.z.x = 0;
	transMat.w.x = local.x;

	transMat.x.y = local.rot.mSinTheta;
	transMat.y.y = local.rot.mCosTheta;
	transMat.z.y = 0;
	transMat.w.y = local.y;
	
	transMat.x.z = 0;
	transMat.y.z = 0;
	transMat.z.z = 1;
	transMat.w.z = 0;

	transMat.x.w = 0;
	transMat.y.w = 0;
	transMat.z.w = 0;
	transMat.w.w = 1;
	glLoadMatrixf((float*)&transMat);

	float drawData[] = {
		-rect.cx,   -rect.cy,   0,  u0, v1, 
		hx-rect.cx, -rect.cy,   0,  u1, v1,	
		-rect.cx, hy-rect.cy,   0,  u0, v0,	
		hx-rect.cx, hy-rect.cy, 0,  u1, v0
	};
	
	Android_DrawArray(eTriangleStrip, TEXCRD_BIT, drawData, 4);
	
}

void KDrawManager::GetViewportSize(unsigned int& width, unsigned int& height)
{
	width = g_viewportWidth;
	height = g_viewportHeight;
}